package com.reebake.ideal.message.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.reebake.ideal.json.util.JsonUtil;
import com.reebake.ideal.message.entity.*;
import com.reebake.ideal.message.core.MessageMediumTypeConstants;
import com.reebake.ideal.message.core.MessageStatusConstants;
import com.reebake.ideal.message.event.MessageDeliveryEvent;
import com.reebake.ideal.message.mapper.MessageNotificationMapper;
import com.reebake.ideal.message.mapper.MessageTemplateMapper;
import com.reebake.ideal.message.service.MessageHistoryService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.reebake.ideal.message.service.MessageOperationService;
import com.reebake.ideal.template.util.TemplateHelper;
import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class MessageOperationServiceImpl implements MessageOperationService {
	
	private final ApplicationEventPublisher applicationEventPublisher;
	private final MessageTemplateMapper messageTemplateMapper;
	private final MessageHistoryService messageHistoryService;
	private final MessageNotificationMapper messageNotificationMapper;
	private static final TemplateEngine templateEngine = TemplateUtil.createEngine(new TemplateConfig());
	
	private MessageTemplate findTemplateByTemplateCode(String templateCode) {
		LambdaQueryWrapper<MessageTemplate> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MessageTemplate::getTemplateCode, templateCode);
		
		return messageTemplateMapper.selectOne(queryWrapper);
	}
	private MessageTemplate findTemplateByMessageType(String mediumType, String messageType) {
		LambdaQueryWrapper<MessageTemplate> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MessageTemplate::getMediumType, mediumType).eq(MessageTemplate::getMessageType, messageType);

		return messageTemplateMapper.selectOne(queryWrapper);
	}
	
	public void sendTemplate(TemplateMessageSendDTO templateMessageSendDTO) {
		MessageTemplate messageTemplate = null;
		String templateCode = templateMessageSendDTO.getTemplateCode();
		String receiverIds = templateMessageSendDTO.getReceiverIds();
		if(StrUtil.isBlank(templateCode)){
			String mediumType = templateMessageSendDTO.getMediumType();
			String messageType = templateMessageSendDTO.getMessageType();
			if(StrUtil.isBlank(mediumType)){
				if(Validator.isMobile(receiverIds)){
					mediumType = MessageMediumTypeConstants.SMS;
				}else if(Validator.isEmail(receiverIds)){
					mediumType = MessageMediumTypeConstants.MAIL;
				}else{
					mediumType = MessageMediumTypeConstants.APP;
				}
			}
			messageTemplate = findTemplateByMessageType(mediumType, messageType);
			templateCode = messageTemplate.getTemplateCode();
		}else {
			messageTemplate = findTemplateByTemplateCode(templateCode);
		}
		Assert.notNull(messageTemplate, "没有找到模板信息");
		
		LinkedHashMap<String, String> configData = new LinkedHashMap<>();
		if(StrUtil.isNotBlank(messageTemplate.getParam())) {
			configData = JsonUtil.toBean(messageTemplate.getParam(), new TypeReference<LinkedHashMap<String, String>>() {
			});
		}
		templateMessageSendDTO.getParam().putAll(configData);
		
		String nowTimeStr = LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DatePattern.NORM_TIME_FORMATTER);
		LocalDateTime nowTime = LocalDateTimeUtil.parse(nowTimeStr, DatePattern.NORM_TIME_FORMATTER);
		Boolean enablePending = messageTemplate.getEnablePending();
		boolean enableEnterPool = false;
		if(StrUtil.isNotBlank(messageTemplate.getDeliveryStartTime())) {
			LocalDateTime deliveryStartTime = LocalDateTimeUtil.parse(messageTemplate.getDeliveryStartTime(), DatePattern.NORM_TIME_FORMATTER);
			if(nowTime.isBefore(deliveryStartTime)) {
				enableEnterPool = true;
			}
		}
		if(StrUtil.isNotBlank(messageTemplate.getDeliveryEndTime())) {
			LocalDateTime deliveryEndTime = LocalDateTimeUtil.parse(messageTemplate.getDeliveryEndTime(), DatePattern.NORM_TIME_FORMATTER);
			if(nowTime.isAfter(deliveryEndTime)) {
				enableEnterPool = true;
			}
		}

        Map<String, Object> renderData = new LinkedHashMap<>(templateMessageSendDTO.getParam());
		TemplateHelper.initStaticModels(renderData);
		String title = messageTemplate.getTitle();
		if(StrUtil.isNotBlank(title)) {
			Template titleTemplate = templateEngine.getTemplate(title);
			title = titleTemplate.render(renderData);
		}
		
		String content = messageTemplate.getContent();
		if(StrUtil.isNotBlank(content)) {
			Template contentTemplate = templateEngine.getTemplate(content);
			content = contentTemplate.render(renderData);
		}
		
		String attachments = messageTemplate.getAttachments();
		if(StrUtil.isNotBlank(templateMessageSendDTO.getAttachments())) {
			attachments = templateMessageSendDTO.getAttachments();
		}
		
		MessageHistory messageHistory = new MessageHistory();
		messageHistory.setBizType(messageTemplate.getBizType());
		messageHistory.setChannelId(messageTemplate.getChannelId());
		messageHistory.setContent(content);
		messageHistory.setMediumType(messageTemplate.getMediumType());
		messageHistory.setMessageGroup(messageTemplate.getMessageGroup());
		messageHistory.setMessageTemplateId(messageTemplate.getMessageTemplateId());
		messageHistory.setMessageType(messageTemplate.getMessageType());
		messageHistory.setOutTemplateId(messageTemplate.getOutTemplateId());
		messageHistory.setSendTime(DateUtil.date());
		messageHistory.setStatus(MessageStatusConstants.SUCCESS);
		messageHistory.setTitle(title);
		messageHistory.setSenderId(templateMessageSendDTO.getSenderId());
		messageHistory.setAttachments(attachments);

		MessageDeliveryDTO messageDeliveryDTO = new MessageDeliveryDTO();
		messageDeliveryDTO.setAttachments(attachments);
		messageDeliveryDTO.setContent(content);
		messageDeliveryDTO.setMediumType(messageHistory.getMediumType());
		messageDeliveryDTO.setMessageGroup(messageHistory.getMessageGroup());
		messageDeliveryDTO.setMessageType(messageHistory.getMessageType());
		messageDeliveryDTO.setBizType(messageHistory.getBizType());
		messageDeliveryDTO.setChannelId(messageHistory.getChannelId());
		messageDeliveryDTO.setOutTemplateId(messageHistory.getOutTemplateId());
		messageDeliveryDTO.setMessageTemplateId(messageHistory.getMessageTemplateId());
		messageDeliveryDTO.setTitle(title);
		messageDeliveryDTO.setIsBatchSend(messageTemplate.getIsBatchSend());
		messageDeliveryDTO.setEnableDelivery(messageTemplate.getEnableDelivery());
		messageDeliveryDTO.setParam(templateMessageSendDTO.getParam());
		messageDeliveryDTO.setEnableNotification(messageTemplate.getEnableNotification());
		messageDeliveryDTO.setSenderId(templateMessageSendDTO.getSenderId());
		messageDeliveryDTO.setSenderName(templateMessageSendDTO.getSenderName());
		messageDeliveryDTO.setSenderAvatar(templateMessageSendDTO.getSenderAvatar());

		Boolean isSeparateSend = messageTemplate.getIsSeparateSend();
		if(BooleanUtil.isTrue(isSeparateSend)) {
			for (String receiverId : StrUtil.split(templateMessageSendDTO.getReceiverIds(), ";")) {
				doSend(receiverId, messageDeliveryDTO, messageHistory);
			}
		}else{
			doSend(templateMessageSendDTO.getReceiverIds(), messageDeliveryDTO, messageHistory);
		}
	}

	@Override
	public void send(MessageSendDTO messageSendDTO) {
		MessageDeliveryDTO messageDeliveryDTO = new MessageDeliveryDTO();
		messageDeliveryDTO.setAttachments(messageSendDTO.getAttachments());
		messageDeliveryDTO.setContent(messageSendDTO.getContent());
		messageDeliveryDTO.setMediumType(messageSendDTO.getMediumType());
		messageDeliveryDTO.setMessageGroup(messageSendDTO.getMessageGroup());
		messageDeliveryDTO.setMessageType(messageSendDTO.getMessageType());
		messageDeliveryDTO.setBizType(messageSendDTO.getBizType());
		messageDeliveryDTO.setChannelId(messageSendDTO.getChannelId());
		messageDeliveryDTO.setOutTemplateId(messageSendDTO.getOutTemplateId());
		messageDeliveryDTO.setMessageTemplateId(null);
		messageDeliveryDTO.setTitle(messageSendDTO.getTitle());
		messageDeliveryDTO.setIsBatchSend(messageSendDTO.getIsBatchSend());
		messageDeliveryDTO.setEnableDelivery(null);
		messageDeliveryDTO.setParam(messageSendDTO.getParam());
		messageDeliveryDTO.setSenderId(messageSendDTO.getSenderId());
		messageDeliveryDTO.setSenderName(messageSendDTO.getSenderName());
		messageDeliveryDTO.setSenderAvatar(messageSendDTO.getSenderAvatar());
		messageDeliveryDTO.setEnableNotification(messageSendDTO.getEnableNotification());

		Boolean isSeparateSend = messageSendDTO.getIsSeparateSend();
		if(BooleanUtil.isTrue(isSeparateSend)) {
			for (String receiverId : StrUtil.split(messageSendDTO.getReceiverIds(), ";")) {
				doSend(receiverId, messageDeliveryDTO, null);
			}
		}else{
			doSend(messageSendDTO.getReceiverIds(), messageDeliveryDTO, null);
		}
	}

	private void doSend(String receiverId, MessageDeliveryDTO messageDeliveryDTO, @Nullable MessageHistory messageHistory){
		if(messageHistory != null) {
			messageHistory.setReceiverId(receiverId);
			messageHistoryService.save(messageHistory);
		}

		messageDeliveryDTO.setReceiverIds(receiverId);
		if(messageHistory != null) {
			messageDeliveryDTO.setMessageHistoryId(messageHistory.getMessageHistoryId());
		}

		if(BooleanUtil.isTrue(messageDeliveryDTO.getEnableNotification())) {
			MessageNotification messageNotification = new MessageNotification();
			messageNotification.setMessageGroup(messageDeliveryDTO.getMessageGroup());
			messageNotification.setMessageHistoryId(messageDeliveryDTO.getMessageHistoryId());
			messageNotification.setMessageType(messageDeliveryDTO.getMessageType());
			messageNotification.setContent(messageDeliveryDTO.getContent());
			messageNotification.setBizType(messageDeliveryDTO.getBizType());
			messageNotification.setReceiverId(messageDeliveryDTO.getReceiverIds());
			messageNotification.setSenderId(messageDeliveryDTO.getSenderId());
			messageNotification.setSenderAvatar(messageDeliveryDTO.getSenderAvatar());
			messageNotification.setSenderName(messageDeliveryDTO.getSenderName());
			messageNotification.setSendTime(DateUtil.date());
			messageNotification.setTitle(messageDeliveryDTO.getTitle());

			messageNotificationMapper.insert(messageNotification);
		}

		applicationEventPublisher.publishEvent(new MessageDeliveryEvent(this, messageDeliveryDTO));
	}
}
